import ajax from './ajax'

const websocket = {

  wsQueue: {},

  /**
   * 生成一个用不重复的ID
   * @param { Number } randomLength
   */
  getUuiD(randomLength) {
    return Number(Math.random().toString().substr(2, randomLength) + Date.now()).toString(36)
  },

  /**
   * 添加新增加的ws对象
   * @param ws
   */
  addWs(ws) {
    this.wsQueue[ws.name] = ws;
  },

  /**
   * 移除ws对象
   * @param ws
   */
  removeWs(ws) {
    delete this.wsQueue[ws.name];
  },

  /**
   * 获取ws对象
   * @param name
   */
  getWs(name) {
    return this.wsQueue[name];
  },


  /**
   * 初始化websocket连接服务
   * @param wsName 构建websocket链接名称
   * @param contextPath 对应每个子系统服务的contextPath路径，有则添加，无则不管。
   * 1：引入改组件并调用initWebSocket()，返回ws对象。
   * 2：需要显示调用ws对象中的connection()函数，并传入当前界面需要监听的topic以及回调函数，格式可以传入多个topic数据或则单个topic对象。
   *    >>>>>例如{topic:xxxx,callback:(msg)=>{}}或则[{topic:xxxx,callback:(msg)=>{}},{topic:xxxx,callback:(msg)=>{}}]
   * 3：如当前界面需要在跳转界面后需要将传输断开的话，需要显示调用ws对象的disconnect()函数，推出后会自动销毁定时器、连接对象等
   */
  initWebSocket(wsName, contextPath) {
    let ws = this.getWs(wsName);
    if (ws) {
      return ws;
    }
    ws = {
      sub: 'sub',
      disSub: 'disSub',
      timer: null, //定时器对象
      //model对象，模块标识和更新语句柄=======>key：模块标识，value：标识对应的函数句柄或则回调函数，如：{modelName1：(msg) => {}, modelName2: (msg) => {}}
      smallModel: {},
      //socketJs对象
      socket: {},
      //socket链接是否open开启
      socketOpen: false,
      //websocket 服务路径
      baseUrl: '/ueye/websocketJS',
      //初始化请求连接地址
      url: "",
      //ws协议对象名
      name: wsName ? wsName : 'ws_' + websocket.getUuiD(20),
      /**
       * 连接ws服务
       * @param subscribe 订阅topic
       * @param header 定义客户端的认证信息,按需求配置
       */
      connection() {
        let that = this;
        if (contextPath){
          if (!contextPath.startsWith('/')){
            contextPath = '/'+contextPath;
          }
          that.url = contextPath;
        }
          //判断浏览器是否支持websocket协议
          if (typeof WebSocket != 'undefined') {
            console.log("您的浏览器支持Websocket通信协议")
            ajax.post(that.url + '/wsServer/getSystemUrl', {}).then(res => {
              let url = res.data;
              //获取本地token信息
              let token = localStorage.getItem("token");
              if (!token || token == 'undefined'){
                token = Math.random();
              }
              that.socket = new WebSocket(url + that.url +that.baseUrl + "/" +token);
              //初始化websocket链接时，向服务器发送链接请求。
              that.socket.onopen = (res) => {
                that.socketOpen = true;
                if (that.timer){
                  clearInterval(that.timer)
                }
                console.log("websocket服务链接成功......................", that.socket.readyState,"websocket状态",WebSocket.OPEN)
              };
              //websocket服务接收消息监听钩子函数
              that.socket.onmessage = (res) => {
                const content = JSON.parse(res.data);
                //判断当前订阅消息内容是否为数组，如果是数组则遍历执行
                if (Array.isArray(content)) {
                  for (let item of content) {
                    for (let smallModelKey in that.smallModel) {
                      let callback = that.smallModel[smallModelKey][content.topic];
                      if (callback){
                        callback(content.msg)
                        break;
                      }
                    }
                  }
                } else {
                  for (let smallModelKey in that.smallModel) {
                    let callback = that.smallModel[smallModelKey][content.topic];
                    if (callback){
                      callback(content.msg)
                      break;
                    }
                  }
                }
                console.log("websocket消息来了......................")
              };
              //websocket链接异常报错时钩子函数
              that.socket.onerror = (e) => {
                //失败重连操作.......
                that.reconnect();
                console.log("websocket出现异常......................",e)
              };
              //关闭websocket链接
              that.socket.onclose = (res) => {
                //清除订阅者，//清楚订阅模块
                Object.keys(that.smallModel).forEach(key => {
                  delete that.smallModel[key];
                });
                //清除ws对象
                websocket.removeWs(that.name);
                that.socket = null;
                that.socketOpen = false;
                console.log("websocket链接关闭了......................")
              }
            })

          }else{
            alert("您的浏览器不支持Websocket通信协议，请使用Chrome或者Firefox浏览器！");
          }
      },
        /**
         * 获取当前socket使用状态
         * @returns {boolean}
         */
        getSocketSate(){
          if (this.socket){
              return this.socket.readyState == WebSocket.OPEN;
          }
          return false;
        },

      /**
       * 从连socket服务
       * @param socketUrl 链接访问路径地址
       * @param header 重新链接请求头
       */
      reconnect () {
        let that = this;
        if(!that.timer){
          that.timer = setInterval(() => {
            that.connection()
          }, 2000);
        }
      },

      /***
       * 订阅指定主题消息内容
       * @param topic 主题
       * @param modelName 模块名称
       * @param callback 回调函数
       * @param param 订阅参数对象，用于过滤推送时的数据
       */
      subscribe(topic, modelName, callback, param) {
        let subscribe = {
          topic: topic,
          model: {}
        }
        param = param ? {} : param;
        let that = this;
        subscribe.model[modelName] = callback;
        //判断链接状态，链接成功后才进行主题订阅
        if (this.getSocketSate()) {
          //发送订阅请求
          let subscribeReq = {
            op: that.sub,
            topic: topic,
            model: modelName,
            param: param
          }
          this.sendMsg(subscribeReq)
          let model = this.smallModel[topic];
          if (!model){
            model = {};
          }
          this.smallModel[topic] = {...model, ...subscribe.model};
          console.log("主题【"+topic+"】事件订阅成功");
        } else {
          console.log("当前socketJs未连接，请先执行connection()函数。");
          if (!this.socketOpen){
              this.connection();
          }
          let timer = window.setTimeout(() => {
            window.clearInterval(timer);
            this.subscribe(topic, modelName, callback, param);
          }, 1000);
        }
      },

      /**
       * 订阅指定主题消息，根据模块标识，来区分模块和对应需要执行的函数句柄。
       * @param topic 主题名
       * @param model 模块标识和更新语句柄=======>key：模块标识，value：标识对应的函数句柄或则回调函数，如：{modelName1：(msg) => {}, modelName2: (msg) => {}}
       * @param param 订阅参数对象，用于过滤推送时的数据
       */
      subscribeToModel(topic, model, param) {
        //组装订阅参数
        let subscribe = {
          topic: topic,
          model: model
        }
        param =  param ? {} : param;
        let that = this;
        //判断当前链接是否正常可用，如果不可用则重新进行链接
        if (this.getSocketSate()) {
          //模块标识集合，用于下发订阅参数
          let modularFlag = [];
          //将模块标识在model中提取出来，并放入订阅header中。
          Object.keys(model).forEach(key => { modularFlag.push(key) });
          //发布订阅请求
            //发送订阅请求
            let subscribeReq = {
              op: that.sub,
              topic: topic,
              model: modularFlag.join(","),
              param: param
            }
            this.sendMsg(subscribeReq);
            let oldModel = this.smallModel[topic];
            if (!oldModel){
              oldModel = {};
            }
            this.smallModel[topic] = {...oldModel, ...model}
            console.log("主题【"+topic+"】事件订阅成功");
        } else {
          console.log("当前socketJs未连接，请先执行connection()函数。");
            if (!this.socketOpen){
                this.connection();
            }
            let timer = window.setTimeout(() => {
                window.clearInterval(timer);
                this.subscribeToModel(topic, model, param);
            }, 1000);
        }
      },

      /**
       * 取消指定topic订阅监听者
       * @param topic
       */
      unSubscribe(topic) {
        //发送取消订阅请求
        let that = this;
        let unSubscribeReq = {
          op: that.disSub,
          topic: topic,
        }
        this.sendMsg(unSubscribeReq);
        delete this.smallModel[topic];
        console.log("取消主题：【" + topic + "】订阅")
      },

      /**
       * 断开连接
       */
      disconnect() {
        let that = this;
        if (that.socket != null) {
          //断开连接
          that.socket.close();
        }
      },
      /**
       * 发送消息
       * @param param 请求参数
       */
      sendMsg(param) {
        if (this.getSocketSate()){
            try {
                return this.socket.send(JSON.stringify(param));
            }catch (e) {
                console.log(e)
            }
        }
      },
    }
    //初始化链接
    ws.connection();
    websocket.addWs(ws);
    return ws;
  },
}
export default websocket;
